﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;

using Neat.Mathematics;
namespace RiverRaidDesigner
{
   
    public partial class Form1 : Form
    {
        int yOffset = 0;
        int yScrollSpeed = 8;
        int gridSize = 10;
        List<Point> outerWalls;
        List<Point> innerWalls;
        bool showGrid = false;
        Color gridColor;
        bool _interiorMode = false;
        bool wallMode = true;
        bool interiorMode { get { return _interiorMode; } set { _interiorMode = value; wallMode = true; } }
        Items _selectedItem = Items.Fuel;
        Items selectedItem { get { return _selectedItem; } set { _selectedItem = value; wallMode = false; } }
        Pen gridPen;
        float imageScale = 0.4f;
        bool _flipDirection = false;
        bool flipDirection { get { return _flipDirection; } set { _flipDirection = value; btnFlip.Checked = flipDirection; } }
        Image fuelImage, shipImage, heliImage, houseImage, treeImage, bridgeImage, jetImage,
            roadImage, raiderImage;
        float bridgeX, bridgeW;
        List<ItemWithPositionAndDirection> items;
        

        public Form1()
        {
            InitializeComponent();
            Reset();
        }

        void Reset()
        {
            outerWalls = new List<Point>();
            innerWalls = new List<Point>();
            items = new List<ItemWithPositionAndDirection>();
            gridColor = Color.FromArgb(20, 0, 0, 0);
            gridPen = new Pen(gridColor, 1);

            yOffset = Height;
            fuelImage = Image.FromFile(@"RiverRaid\fuel.png");
            shipImage = Image.FromFile(@"RiverRaid\ship.png");
            heliImage = Image.FromFile(@"RiverRaid\heli.png");
            houseImage = Image.FromFile(@"RiverRaid\house.png");
            treeImage = Image.FromFile(@"RiverRaid\tree.png");
            bridgeImage = Image.FromFile(@"RiverRaid\bridge.png");
            jetImage = Image.FromFile(@"RiverRaid\jet.png");
            roadImage = Image.FromFile(@"RiverRaid\road.png");
            raiderImage = Image.FromFile(@"RiverRaid\raider.png");
            bridgeW = bridgeImage.Width * imageScale;
            bridgeX = Width / 2 - (bridgeImage.Width * imageScale) / 2;
            outerWalls.Add(new Point((int)(Width / 2 - bridgeX), 0));
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            if (bridgeImage != null)
                bridgeX = Width / 2 - (bridgeImage.Width * imageScale) / 2;
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            MessageBox.Show("Form1_KeyDown");
        }

        private void Form1_KeyPress(object sender, KeyPressEventArgs e)
        {
            MessageBox.Show("Form1_KeyPress");
        }

        private void toolStrip1_KeyDown(object sender, KeyEventArgs e)
        {
            MessageBox.Show("toolStrip1_KeyDown");
        }

        private void toolStrip1_KeyPress(object sender, KeyPressEventArgs e)
        {
            MessageBox.Show("toolStrip1_KeyPress");
        }

        private void toolStripContainer1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.W)
                yOffset -= yScrollSpeed;
            if (e.KeyCode == Keys.S)
                yOffset += yScrollSpeed;
            if (e.KeyCode == Keys.I)
                interiorMode = true;
            if (e.KeyCode == Keys.O)
                interiorMode = false;
            if (e.KeyCode == Keys.F1)
                selectedItem = Items.Fuel;
            if (e.KeyCode == Keys.F2)
                selectedItem = Items.Ship;
            if (e.KeyCode == Keys.F3)
                selectedItem = Items.Heli;
            if (e.KeyCode == Keys.F4)
                selectedItem = Items.Tree;
            if (e.KeyCode == Keys.F5)
                selectedItem = Items.Jet;
            if (e.KeyCode == Keys.F6)
                selectedItem = Items.House;
            if (e.KeyCode == Keys.F7)
                selectedItem = Items.Bridge;
            if (e.KeyCode == Keys.Oemtilde)
                flipDirection = !flipDirection;
            UpdateToolbar();
            Render();

        }

        void UpdateToolbar()
        {
            btnFuel.Checked = btnShip.Checked = btnHeli.Checked =
                btnHouse.Checked = btnTree.Checked = btnBridge.Checked =
                btnJet.Checked = false;
            if (selectedItem == Items.Fuel)
                btnFuel.Checked = true;
            else if (selectedItem == Items.Ship)
                btnShip.Checked = true;
            else if (selectedItem == Items.Heli)
                btnHeli.Checked = true;
            else if (selectedItem == Items.House)
                btnHouse.Checked = true;
            else if (selectedItem == Items.Tree)
                btnTree.Checked = true;
            else if (selectedItem == Items.Bridge)
                btnBridge.Checked = true;
            else btnJet.Checked = true;
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            
        }

        private void toolStripContainer1_KeyPress(object sender, KeyPressEventArgs e)
        {

        }

        private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
        {
            mousePos = spanMouse(e.Location);

            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (wallMode)
                {
                    if (interiorMode)
                    {
                        var p = new Point(Math.Abs(Width / 2 - mousePos.X), mousePos.Y - yOffset);
                        innerWalls.Add(p);
                    }
                    else
                    {
                        var p = new Point(
                            //(Width / 2 > mousePos.X ? mousePos.X : Width - mousePos.X), mousePos.Y - yOffset);
                            Math.Abs(Width/2 - mousePos.X), mousePos.Y - yOffset);
                        outerWalls.Add(p);
                    }
                }
                else
                {
                    Point p = new Point(Width/2 - mousePos.X, mousePos.Y - yOffset);
                    items.Add(new ItemWithPositionAndDirection(selectedItem, p, flipDirection));
                }
            }
            else if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                if (wallMode)
                {
                    if (interiorMode && innerWalls.Count > 0) innerWalls.RemoveAt(innerWalls.Count - 1);
                    else if (!interiorMode && outerWalls.Count > 0) outerWalls.RemoveAt(outerWalls.Count - 1);
                }
                else
                {
                    for (int i = 0; i < items.Count; i++)
                    {
                        Image img = GetImage(items[i].itemType);
                        Microsoft.Xna.Framework.Rectangle r = new Microsoft.Xna.Framework.Rectangle(
                            Width/2 - items[i].position.X, items[i].position.Y + yOffset, (int)(img.Width * imageScale), (int)(img.Height * imageScale));
                        if (r.Contains(e.Location.X, e.Location.Y))
                        {
                            items.RemoveAt(i);
                            break;
                        }
                    }
                }
            }
            Render();
        }

        void Render()
        {
            pictureBox1.Refresh();
            lblWallMode.Text = (interiorMode ? "INTERIOR" : "EXTERIOR");
            lblYOffset.Text = yOffset.ToString();
        }

        Image GetImage(Items item)
        {
            if (item == Items.Bridge) return bridgeImage;
            else if (item == Items.Fuel) return fuelImage;
            else if (item == Items.House) return houseImage;
            else if (item == Items.Heli) return heliImage;
            else if (item == Items.Jet) return jetImage;
            else if (item == Items.Ship) return shipImage;
            else if (item == Items.Tree) return treeImage;
            else return raiderImage;
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            var g = e.Graphics;// pictureBox1.CreateGraphics();
            g.Clear(Color.CornflowerBlue);
            g.DrawString("Testing", SystemFonts.DefaultFont, Brushes.Black, new PointF(10, 10));

            if (showGrid)
            {
                for (int i = 0; i < Width; i += gridSize)
                    g.DrawLine(gridPen, i, 0, i, Height);
                for (int i = 0; i < Height; i += gridSize)
                    g.DrawLine(gridPen, 0, i, Width, i);
            }

            g.DrawImage(raiderImage, new Rectangle((int)(Width - raiderImage.Width * imageScale) / 2, Height - 200, (int)(raiderImage.Width * imageScale), (int)(raiderImage.Height * imageScale)));


            g.DrawLine(Pens.Gold, bridgeX, 0, bridgeX, Height);
            g.DrawLine(Pens.Gold, bridgeX + bridgeW, 0, bridgeX + bridgeW, Height);

            for (int i = 1; i < outerWalls.Count; i++)
            {
                int wallWidth = (int)(Width / 2.0f - outerWalls[i - 1].X);
                g.FillRectangle(Brushes.LawnGreen,
                    0, (int)(outerWalls[i].Y + yOffset),
                        //(int)(outerWalls[i - 1].X), //OLD EXTERIOR WIDTH
                        wallWidth,
                        (int)(outerWalls[i - 1].Y - outerWalls[i].Y));
                g.FillRectangle(Brushes.LawnGreen,
                    //(int)(Width - outerWalls[i - 1].X), 
                    (int)(Width/2.0f + outerWalls[i-1].X),
                    (int)(outerWalls[i].Y + yOffset),
                       //(int)(outerWalls[i - 1].X), 
                       (int)(Width - (Width/2.0f + outerWalls[i-1].X)),
                       (int)(outerWalls[i - 1].Y - outerWalls[i].Y));
            }
            
            for (int i = 1; i < innerWalls.Count; i++)
            {
                if (innerWalls[i - 1].X == 0) continue;
                g.FillRectangle(Brushes.LawnGreen,
                    (int)((Width / 2) - innerWalls[i - 1].X), (int)(innerWalls[i].Y + yOffset),
                        (int)(2 * innerWalls[i - 1].X), (int)(innerWalls[i - 1].Y - innerWalls[i].Y));
                
            }

            g.DrawLine(Pens.Blue, Width / 2, 0, Width / 2, Height);

            if (wallMode)
            {
                if (interiorMode)
                {
                    if (innerWalls.Count > 0)
                    {
                        var i = innerWalls.Count;
                        g.FillRectangle(Brushes.Green,
                            (int)((Width / 2) - innerWalls[i - 1].X), mousePos.Y,
                            (int)(2 * innerWalls[i - 1].X), (int)((innerWalls[i - 1].Y + yOffset) - mousePos.Y));

                    }
                    g.DrawLine(Pens.Black, mousePos.X, mousePos.Y,
                       Width - mousePos.X, mousePos.Y);
                }
                else
                {
                    if (outerWalls.Count > 0)
                    {
                        var i = outerWalls.Count;
                        g.FillRectangle(Brushes.Green,
                            0, mousePos.Y,
                                //(int)(outerWalls[i - 1].X), //OLD EXTERIOR WIDTH
                                (int)(Width/2.0f - outerWalls[i-1].X),
                                (int)((outerWalls[i - 1].Y + yOffset) - mousePos.Y));
                        g.FillRectangle(Brushes.Green,
                            //(int)(Width - outerWalls[i - 1].X), //OLD EXTERIOR X
                            (int)(Width / 2.0f + outerWalls[i-1].X),
                            mousePos.Y,
                               //(int)(outerWalls[i - 1].X), //OLD EXTERIOR WIDTH
                               (int)(Width - (Width / 2.0f + outerWalls[i-1].X)),
                               (int)((outerWalls[i - 1].Y + yOffset) - mousePos.Y));

                    }
                    g.DrawLine(Pens.Black, 0, mousePos.Y,
                        (Width / 2 > mousePos.X ? mousePos.X : Width - mousePos.X), mousePos.Y);
                    g.DrawLine(Pens.Black, Width, mousePos.Y,
                        (Width / 2 > mousePos.X ? Width - mousePos.X : mousePos.X), mousePos.Y);
                }
            }

            for (int i = 0; i < items.Count; i++)
            {
                ItemWithPositionAndDirection item = items[i];
                Image img = GetImage(item.itemType);
                
                if (item.flipDirection)
                {
                    img = (Image)img.Clone();
                    img.RotateFlip(RotateFlipType.RotateNoneFlipX);
                }

                g.DrawImage(img, Width / 2 - item.position.X, item.position.Y + yOffset, img.Width * imageScale, img.Height * imageScale);
            }

            if (!wallMode)
            {
                float[][] matrixAlpha =  {   
                    new float[] {1, 0, 0, 0, 0},
                    new float[] {0, 1, 0, 0, 0},
                    new float[] {0, 0, 1, 0, 0},
                    new float[] {0, 0, 0, 0.5f, 0},
                    new float[] {0, 0, 0, 0, 1}  
                    };   
                ColorMatrix colorMatrix = new ColorMatrix( matrixAlpha );  
                ImageAttributes iaAlphaBlend = new ImageAttributes();  
                iaAlphaBlend.SetColorMatrix(   colorMatrix,   ColorMatrixFlag.Default,   ColorAdjustType.Bitmap );
                Image img = GetImage(selectedItem);
                if (flipDirection) { img = (Image)img.Clone(); img.RotateFlip(RotateFlipType.RotateNoneFlipX); }
                g.DrawImage(img, new Rectangle((int)mousePos.X, (int)mousePos.Y, (int)(img.Width * imageScale), (int)(img.Height * imageScale)),
                    0, 0, img.Width, img.Height, GraphicsUnit.Pixel, iaAlphaBlend);
            }

            int min = 0, max = 0;
            if (innerWalls.Count > 0 && outerWalls.Count > 0)
            {
                min = Math.Min(innerWalls[innerWalls.Count - 1].X, outerWalls[outerWalls.Count - 1].X);
                max = Math.Max(innerWalls[0].X, outerWalls[0].X);
            }
            else if (outerWalls.Count > 0)
            {
                min = outerWalls[outerWalls.Count - 1].X;
                max = outerWalls[0].X;
            }
            else if (innerWalls.Count > 0)
            {
                min = innerWalls[innerWalls.Count - 1].X;
                max = innerWalls[0].X;
            }
            //if (min != max)
                for (int i = min; i < max; i += 100)
                {
                    g.DrawString(i.ToString(), SystemFonts.DefaultFont, Brushes.Black, 5, yOffset - i);
                }

            g.DrawLine(Pens.Thistle, mousePos.X, 0, mousePos.X, Height);
            g.DrawLine(Pens.Thistle,Width- mousePos.X, 0,Width- mousePos.X, Height);

            g.DrawLine(new Pen(Color.Red, 3), mousePos.X - 5, mousePos.Y, mousePos.X + 5, mousePos.Y);
            g.DrawLine(new Pen(Color.Red, 3), mousePos.X, mousePos.Y-5, mousePos.X, mousePos.Y+5);
            g.DrawLine(new Pen(Color.Red, 1), 0, mousePos.Y - 5, Width, mousePos.Y - 5);

            g.DrawLine(new Pen(Color.Black, 1), (Width - 1280) / 2, 0, (Width - 1280) / 2, Height);
            g.DrawLine(new Pen(Color.Black, 1), (Width - 1280) / 2 + 1280, 0, (Width - 1280) / 2 + 1280, Height);
            g.Flush();
        }

        Point mousePos;
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            mousePos = spanMouse(e.Location);

            lblMousePos.Text = "MOUSE: " + e.Location.X.ToString() + "," + e.Location.Y.ToString()
                + " CROSSHAIR: " + mousePos.X.ToString() + "," + mousePos.Y.ToString();
            Render();
        }

        Point spanMouse(Point m)
        {
            var p = new Point((m.X / gridSize) * gridSize, (m.Y / gridSize) * gridSize);
            if (Math.Abs(p.X - Width / 2) < 5) p.X = Width / 2;
            if (Math.Abs(p.X - bridgeX) < 5) p.X = (int)bridgeX;
            if (Math.Abs(p.X - (bridgeX + bridgeW)) < 5) p.X = (int)(bridgeX + bridgeW);
            return p;
        }

        private void toolStripButton9_Click(object sender, EventArgs e)
        {
            interiorMode = true;
        }

        private void toolStripButton10_Click(object sender, EventArgs e)
        {
            interiorMode = false;
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            saveFileDialog1.ShowDialog();
            StreamWriter sw = new StreamWriter(saveFileDialog1.FileName);
            sw.WriteLine("~2");
            sw.WriteLine("~inner");
            foreach (var item in innerWalls)
                sw.WriteLine(item.X.ToString() + "," + item.Y.ToString());
            sw.WriteLine("~outer");
            foreach (var item in outerWalls)
                sw.WriteLine(item.X.ToString() + "," + item.Y.ToString());
            sw.WriteLine("~entities");
            foreach (var item in items)
            {
                sw.WriteLine(item.position.X.ToString() + "," + item.position.Y.ToString());
                sw.WriteLine(item.flipDirection.ToString());
                sw.WriteLine((char)(item.itemType));
            }
            sw.Close();
        }

        void LoadMap(string filename)
        {
            int version = 1;
            Reset();
            StreamReader sr = new StreamReader(filename);
            var versionId = sr.ReadLine();
            if (versionId.Trim() == "~2")
            {
                versionId = sr.ReadLine();
                version = 2;
            }
            if (versionId != "~inner")
            {
                MessageBox.Show("File is damaged");
                sr.Close();
                return;
            }
            string s;
            while ((s = sr.ReadLine().Trim()) != "~outer")
            {
                Microsoft.Xna.Framework.Point p = Neat.Mathematics.GeometryHelper.String2Point(s);
                innerWalls.Add(new Point(p.X, p.Y));
            }
            while ((s = sr.ReadLine().Trim()) != "~entities")
            {
                Microsoft.Xna.Framework.Point p = Neat.Mathematics.GeometryHelper.String2Point(s);
                if (version == 2)
                    outerWalls.Add(new Point(p.X, p.Y));
                else if (version == 1)
                    outerWalls.Add(new Point(1280 / 2 - Math.Abs(p.X), p.Y));
            }
            while (!sr.EndOfStream)
            {
                Microsoft.Xna.Framework.Point p = Neat.Mathematics.GeometryHelper.String2Point(sr.ReadLine());
                Point pos = new Point(p.X, p.Y);
                if (version == 1)
                {
                    pos.X = 1280 / 2 - pos.X;
                }
                bool flip = bool.Parse(sr.ReadLine());
                Items itype = (Items)(sr.ReadLine()[0]);
                items.Add(
                    new ItemWithPositionAndDirection(itype, pos, flip));
            }
            sr.Close();
        }
        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            
            openFileDialog1.ShowDialog();
            LoadMap(openFileDialog1.FileName);
        }

        private void toolStripButton12_Click(object sender, EventArgs e)
        {
            Reset();
        }

        private void btnGrid_Click(object sender, EventArgs e)
        {
            btnGrid.Checked = showGrid = !showGrid;
        }

        private void toolStripContainer1_KeyUp(object sender, KeyEventArgs e)
        {

        }

        private void btnFuel_Click(object sender, EventArgs e)
        {
            selectedItem = Items.Fuel;
            UpdateToolbar();
        }

        private void btnShip_Click(object sender, EventArgs e)
        {
            selectedItem = Items.Ship;
            UpdateToolbar();
        }

        private void btnHeli_Click(object sender, EventArgs e)
        {
            selectedItem = Items.Heli;
            UpdateToolbar();
        }

        private void btnTree_Click(object sender, EventArgs e)
        {
            selectedItem = Items.Tree;
            UpdateToolbar();
        }

        private void btnJet_Click(object sender, EventArgs e)
        {
            selectedItem = Items.Jet;
            UpdateToolbar();
        }

        private void btnHouse_Click(object sender, EventArgs e)
        {
            selectedItem = Items.House;
            UpdateToolbar();
        }

        private void btnBridge_Click(object sender, EventArgs e)
        {
            selectedItem = Items.Bridge;
            UpdateToolbar();
        }

        private void btnFlip_Click(object sender, EventArgs e)
        {
            flipDirection = !flipDirection;
        }

        //RANDOM GENERATOR
        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            RandomLevelGenerator rlg = new RandomLevelGenerator();
            rlg.Generate();
            LoadMap("test.rrx");
        }

    }



}
